#include "encoder.h"
#include <opencv2/opencv.hpp>
//#include "videoThread.h"
// #include <liveMedia.hh>
// #include <GroupsockHelper.hh>
// #include <BasicUsageEnvironment.hh>
// #include <H264VideoRTPSource.hh>
#include <unistd.h>
/* 创建有名管道，写数据 */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
// #include <QDebug>
// 用于初始化。
MPP_RET test_ctx_init(MpiEncMultiCtxInfo *info)
{

    MpiEncTestData *p = &info->ctx;
    MPP_RET ret = MPP_OK;

    // get paramter from cmd
    p->width        = 1280;
    p->height       = 720;
    p->hor_stride   = (MPP_ALIGN(p->width, 16)*3);
    p->ver_stride   = (MPP_ALIGN(p->height, 16));
    p->fmt          = MPP_FMT_BGR888;
    p->type         = MPP_VIDEO_CodingHEVC;
    p->bps          = 0;
    p->bps_min      = 0;
    p->bps_max      = 0;
    p->rc_mode      = MPP_ENC_RC_MODE_VBR;
    p->frame_num    = 1;

    p->gop_mode     = 0;
    p->gop_len      = 5;
    p->vi_len       = 0;

    p->fps_in_flex  = 0;
    p->fps_in_den   = 0;
    p->fps_in_num   = 0;
    p->fps_out_flex = 0;
    p->fps_out_den  = 0;
    p->fps_out_num  = 0;
    p->scene_mode   = 0;
    p->mdinfo_size  = (MPP_VIDEO_CodingHEVC == p->type) ?
                      (MPP_ALIGN(p->hor_stride, 32) >> 5) *
                      (MPP_ALIGN(p->ver_stride, 32) >> 5) * 16 :
                      (MPP_ALIGN(p->hor_stride, 64) >> 6) *
                      (MPP_ALIGN(p->ver_stride, 16) >> 4) * 16;



    // p->fp_input = fopen("/home/orangepi/code/mpp-develop/test/dog_bike_car_448x448.bgr", "rb");
    // if (NULL == p->fp_input) {
    //     mpp_err("failed to open input file %s\n", "/home/orangepi/code/mpp-develop/test/dog_bike_car_448x448.bgr");
    //     mpp_err("create default yuv image for test\n");
    // }
    //     }
    // } 有个指针没有初始化 是数据输入指针  p->fp_input

    //  测试 264 输出
    p->fp_output = fopen("./1.h264", "w+b");
    if (NULL == p->fp_output) {
        mpp_err("failed to open output file %s\n", p->fp_output);
        ret = MPP_ERR_OPEN_FILE;
    }
    // }



    // update resource parameter
    switch (p->fmt & MPP_FRAME_FMT_MASK) {
    case MPP_FMT_YUV420SP:
    case MPP_FMT_YUV420P: {
        p->frame_size = MPP_ALIGN(p->hor_stride, 64) * MPP_ALIGN(p->ver_stride, 64) * 3 / 2;
    } break;

    case MPP_FMT_YUV422_YUYV :
    case MPP_FMT_YUV422_YVYU :
    case MPP_FMT_YUV422_UYVY :
    case MPP_FMT_YUV422_VYUY :
    case MPP_FMT_YUV422P :
    case MPP_FMT_YUV422SP : {
        p->frame_size = MPP_ALIGN(p->hor_stride, 64) * MPP_ALIGN(p->ver_stride, 64) * 2;
    } break;
    case MPP_FMT_RGB444 :
    case MPP_FMT_BGR444 :
    case MPP_FMT_RGB555 :
    case MPP_FMT_BGR555 :
    case MPP_FMT_RGB565 :
    case MPP_FMT_BGR565 :
    case MPP_FMT_RGB888 :
    case MPP_FMT_BGR888 :
    case MPP_FMT_RGB101010 :
    case MPP_FMT_BGR101010 :
    case MPP_FMT_ARGB8888 :
    case MPP_FMT_ABGR8888 :
    case MPP_FMT_BGRA8888 :
    case MPP_FMT_RGBA8888 : {
        p->frame_size = MPP_ALIGN(p->hor_stride, 64) * MPP_ALIGN(p->ver_stride, 64);
    } break;

    default: {
        p->frame_size = MPP_ALIGN(p->hor_stride, 64) * MPP_ALIGN(p->ver_stride, 64) * 4;
    } break;
    }

    if (MPP_FRAME_FMT_IS_FBC(p->fmt)) {
        if ((p->fmt & MPP_FRAME_FBC_MASK) == MPP_FRAME_FBC_AFBC_V1)
            p->header_size = MPP_ALIGN(MPP_ALIGN(p->width, 16) * MPP_ALIGN(p->height, 16) / 16, SZ_4K);
        else
            p->header_size = MPP_ALIGN(p->width, 16) * MPP_ALIGN(p->height, 16) / 16;
    } else {
        p->header_size = 0;
    }

    return ret;
}

MPP_RET test_mpp_enc_cfg_setup(MpiEncMultiCtxInfo *info)
{

    MpiEncTestData *p = &info->ctx;
    MppApi *mpi = p->mpi;
    MppCtx ctx = p->ctx;
    MppEncCfg cfg = p->cfg;
    RK_U32 quiet = 0;
    MPP_RET ret;
    RK_U32 rotation;
    RK_U32 mirroring;
    RK_U32 flip;
    RK_U32 gop_mode = p->gop_mode;
    MppEncRefCfg ref = NULL;

    /* setup default parameter */
    if (p->fps_in_den == 0)
        p->fps_in_den = 1;
    if (p->fps_in_num == 0)
        p->fps_in_num = 15;
    if (p->fps_out_den == 0)
        p->fps_out_den = 1;
    if (p->fps_out_num == 0)
        p->fps_out_num = 15;

    if (!p->bps)
        p->bps = p->width * p->height / 8 * (p->fps_out_num / p->fps_out_den);

    mpp_enc_cfg_set_s32(cfg, "tune:scene_mode", p->scene_mode);

    mpp_enc_cfg_set_s32(cfg, "prep:width", p->width);
    mpp_enc_cfg_set_s32(cfg, "prep:height", p->height);
    mpp_enc_cfg_set_s32(cfg, "prep:hor_stride", p->hor_stride);
    mpp_enc_cfg_set_s32(cfg, "prep:ver_stride", p->ver_stride);
    mpp_enc_cfg_set_s32(cfg, "prep:format", p->fmt);

    mpp_enc_cfg_set_s32(cfg, "rc:mode", p->rc_mode);

    /* fix input / output frame rate */
    mpp_enc_cfg_set_s32(cfg, "rc:fps_in_flex", p->fps_in_flex);
    mpp_enc_cfg_set_s32(cfg, "rc:fps_in_num", p->fps_in_num);
    mpp_enc_cfg_set_s32(cfg, "rc:fps_in_denorm", p->fps_in_den);
    mpp_enc_cfg_set_s32(cfg, "rc:fps_out_flex", p->fps_out_flex);
    mpp_enc_cfg_set_s32(cfg, "rc:fps_out_num", p->fps_out_num);
    mpp_enc_cfg_set_s32(cfg, "rc:fps_out_denorm", p->fps_out_den);

    /* drop frame or not when bitrate overflow */
    mpp_enc_cfg_set_u32(cfg, "rc:drop_mode", MPP_ENC_RC_DROP_FRM_DISABLED);
    mpp_enc_cfg_set_u32(cfg, "rc:drop_thd", 20);        /* 20% of max bps */
    mpp_enc_cfg_set_u32(cfg, "rc:drop_gap", 1);         /* Do not continuous drop frame */

    /* setup bitrate for different rc_mode */
    mpp_enc_cfg_set_s32(cfg, "rc:bps_target", p->bps);
    switch (p->rc_mode) {
    case MPP_ENC_RC_MODE_FIXQP : {
        /* do not setup bitrate on FIXQP mode */
    } break;
    case MPP_ENC_RC_MODE_CBR : {
        /* CBR mode has narrow bound */
        mpp_enc_cfg_set_s32(cfg, "rc:bps_max", p->bps_max ? p->bps_max : p->bps * 17 / 16);
        mpp_enc_cfg_set_s32(cfg, "rc:bps_min", p->bps_min ? p->bps_min : p->bps * 15 / 16);
    } break;
    case MPP_ENC_RC_MODE_VBR :
    case MPP_ENC_RC_MODE_AVBR : {
        /* VBR mode has wide bound */
        mpp_enc_cfg_set_s32(cfg, "rc:bps_max", p->bps_max ? p->bps_max : p->bps * 17 / 16);
        mpp_enc_cfg_set_s32(cfg, "rc:bps_min", p->bps_min ? p->bps_min : p->bps * 1 / 16);
    } break;
    default : {
        /* default use CBR mode */
        mpp_enc_cfg_set_s32(cfg, "rc:bps_max", p->bps_max ? p->bps_max : p->bps * 17 / 16);
        mpp_enc_cfg_set_s32(cfg, "rc:bps_min", p->bps_min ? p->bps_min : p->bps * 15 / 16);
    } break;
    }

    /* setup qp for different codec and rc_mode */
    switch (p->type) {
    case MPP_VIDEO_CodingAVC :
    case MPP_VIDEO_CodingHEVC : {
        switch (p->rc_mode) {
        case MPP_ENC_RC_MODE_FIXQP : {
            RK_S32 fix_qp = 0;

            mpp_enc_cfg_set_s32(cfg, "rc:qp_init", fix_qp);
            mpp_enc_cfg_set_s32(cfg, "rc:qp_max", fix_qp);
            mpp_enc_cfg_set_s32(cfg, "rc:qp_min", fix_qp);
            mpp_enc_cfg_set_s32(cfg, "rc:qp_max_i", fix_qp);
            mpp_enc_cfg_set_s32(cfg, "rc:qp_min_i", fix_qp);
            mpp_enc_cfg_set_s32(cfg, "rc:qp_ip", 0);
            mpp_enc_cfg_set_s32(cfg, "rc:fqp_min_i", fix_qp);
            mpp_enc_cfg_set_s32(cfg, "rc:fqp_max_i", fix_qp);
            mpp_enc_cfg_set_s32(cfg, "rc:fqp_min_p", fix_qp);
            mpp_enc_cfg_set_s32(cfg, "rc:fqp_max_p", fix_qp);
        } break;
        case MPP_ENC_RC_MODE_CBR :
        case MPP_ENC_RC_MODE_VBR :
        case MPP_ENC_RC_MODE_AVBR : {
            mpp_enc_cfg_set_s32(cfg, "rc:qp_init", -1);
            mpp_enc_cfg_set_s32(cfg, "rc:qp_max",  51);
            mpp_enc_cfg_set_s32(cfg, "rc:qp_min",  10);
            mpp_enc_cfg_set_s32(cfg, "rc:qp_max_i",  51);
            mpp_enc_cfg_set_s32(cfg, "rc:qp_min_i",  10);
            mpp_enc_cfg_set_s32(cfg, "rc:qp_ip", 2);
            mpp_enc_cfg_set_s32(cfg, "rc:fqp_min_i",  10);
            mpp_enc_cfg_set_s32(cfg, "rc:fqp_max_i", 51);
            mpp_enc_cfg_set_s32(cfg, "rc:fqp_min_p", 10);
            mpp_enc_cfg_set_s32(cfg, "rc:fqp_max_p",  51);
        } break;
        default : {
            mpp_err_f("unsupport encoder rc mode %d\n", p->rc_mode);
        } break;
        }
    } break;
    case MPP_VIDEO_CodingVP8 : {
        /* vp8 only setup base qp range */
        mpp_enc_cfg_set_s32(cfg, "rc:qp_init", 40);
        mpp_enc_cfg_set_s32(cfg, "rc:qp_max",  127);
        mpp_enc_cfg_set_s32(cfg, "rc:qp_min",  0);
        mpp_enc_cfg_set_s32(cfg, "rc:qp_max_i",127);
        mpp_enc_cfg_set_s32(cfg, "rc:qp_min_i",  0);
        mpp_enc_cfg_set_s32(cfg, "rc:qp_ip", 6);
    } break;
    case MPP_VIDEO_CodingMJPEG : {
        /* jpeg use special codec config to control qtable */
        mpp_enc_cfg_set_s32(cfg, "jpeg:q_factor",  80);
        mpp_enc_cfg_set_s32(cfg, "jpeg:qf_max",  99);
        mpp_enc_cfg_set_s32(cfg, "jpeg:qf_min",  1);
    } break;
    default : {
    } break;
    }

    /* setup codec  */
    mpp_enc_cfg_set_s32(cfg, "codec:type", p->type);
    switch (p->type) {
    case MPP_VIDEO_CodingAVC : {
        RK_U32 constraint_set;

        /*
         * H.264 profile_idc parameter
         * 66  - Baseline profile
         * 77  - Main profile
         * 100 - High profile
         */
        mpp_enc_cfg_set_s32(cfg, "h264:profile", 100);
        /*
         * H.264 level_idc parameter
         * 10 / 11 / 12 / 13    - qcif@15fps / cif@7.5fps / cif@15fps / cif@30fps
         * 20 / 21 / 22         - cif@30fps / half-D1@@25fps / D1@12.5fps
         * 30 / 31 / 32         - D1@25fps / 720p@30fps / 720p@60fps
         * 40 / 41 / 42         - 1080p@30fps / 1080p@30fps / 1080p@60fps
         * 50 / 51 / 52         - 4K@30fps
         */
        mpp_enc_cfg_set_s32(cfg, "h264:level", 40);
        mpp_enc_cfg_set_s32(cfg, "h264:cabac_en", 1);
        mpp_enc_cfg_set_s32(cfg, "h264:cabac_idc", 0);
        mpp_enc_cfg_set_s32(cfg, "h264:trans8x8", 1);

        mpp_env_get_u32("constraint_set", &constraint_set, 0);
        if (constraint_set & 0x3f0000)
            mpp_enc_cfg_set_s32(cfg, "h264:constraint_set", constraint_set);
    } break;
    case MPP_VIDEO_CodingHEVC :
    case MPP_VIDEO_CodingMJPEG :
    case MPP_VIDEO_CodingVP8 : {
    } break;
    default : {
        mpp_err_f("unsupport encoder coding type %d\n", p->type);
    } break;
    }

    p->split_mode = 0;
    p->split_arg = 0;
    p->split_out = 0;

    mpp_env_get_u32("split_mode", &p->split_mode, MPP_ENC_SPLIT_NONE);
    mpp_env_get_u32("split_arg", &p->split_arg, 0);
    mpp_env_get_u32("split_out", &p->split_out, 0);

    if (p->split_mode) {
        mpp_log_q(quiet, "%p split mode %d arg %d out %d\n", ctx,
                  p->split_mode, p->split_arg, p->split_out);
        mpp_enc_cfg_set_s32(cfg, "split:mode", p->split_mode);
        mpp_enc_cfg_set_s32(cfg, "split:arg", p->split_arg);
        mpp_enc_cfg_set_s32(cfg, "split:out", p->split_out);
    }

    mpp_env_get_u32("mirroring", &mirroring, 0);
    mpp_env_get_u32("rotation", &rotation, 0);
    mpp_env_get_u32("flip", &flip, 0);

    mpp_enc_cfg_set_s32(cfg, "prep:mirroring", mirroring);
    mpp_enc_cfg_set_s32(cfg, "prep:rotation", rotation);
    mpp_enc_cfg_set_s32(cfg, "prep:flip", flip);

    // config gop_len and ref cfg
    mpp_enc_cfg_set_s32(cfg, "rc:gop", p->gop_len ? p->gop_len : p->fps_out_num * 2);

    mpp_env_get_u32("gop_mode", &gop_mode, gop_mode);

    if (gop_mode) {
        mpp_enc_ref_cfg_init(&ref);

        if (p->gop_mode < 4)
            mpi_enc_gen_ref_cfg(ref, gop_mode);
        else
            mpi_enc_gen_smart_gop_ref_cfg(ref, p->gop_len, p->vi_len);

        mpp_enc_cfg_set_ptr(cfg, "rc:ref_cfg", ref);
    }

    ret = mpi->control(ctx, MPP_ENC_SET_CFG, cfg);
    if (ret) {
        mpp_err("mpi control enc set cfg failed ret %d\n", ret);
        goto RET;
    }

    if (ref)
        mpp_enc_ref_cfg_deinit(&ref);

    /* optional */
    {
        RK_U32 sei_mode;

        mpp_env_get_u32("sei_mode", &sei_mode, MPP_ENC_SEI_MODE_ONE_FRAME);
        p->sei_mode = (MppEncSeiMode)sei_mode;
        ret = mpi->control(ctx, MPP_ENC_SET_SEI_CFG, &p->sei_mode);
        if (ret) {
            mpp_err("mpi control enc set sei cfg failed ret %d\n", ret);
            goto RET;
        }
    }

    if (p->type == MPP_VIDEO_CodingAVC || p->type == MPP_VIDEO_CodingHEVC) {
        p->header_mode = MPP_ENC_HEADER_MODE_EACH_IDR;
        ret = mpi->control(ctx, MPP_ENC_SET_HEADER_MODE, &p->header_mode);
        if (ret) {
            mpp_err("mpi control enc set header mode failed ret %d\n", ret);
            goto RET;
        }
    }

    /* setup test mode by env */
    mpp_env_get_u32("osd_enable", &p->osd_enable, 0);
    mpp_env_get_u32("osd_mode", &p->osd_mode, MPP_ENC_OSD_PLT_TYPE_DEFAULT);
    mpp_env_get_u32("roi_enable", &p->roi_enable, 0);
    mpp_env_get_u32("user_data_enable", &p->user_data_enable, 0);



RET:
    return ret;
}
MPP_RET test_ctx_deinit(MpiEncTestData *p)
{
    if (p) {
//        if (p->cam_ctx) {
//            camera_source_deinit(p->cam_ctx);
//            p->cam_ctx = NULL;
//        }
        if (p->fp_input) {
            fclose(p->fp_input);
            p->fp_input = NULL;
        }
        if (p->fp_output) {
            fclose(p->fp_output);
            p->fp_output = NULL;
        }
        if (p->fp_verify) {
            fclose(p->fp_verify);
            p->fp_verify = NULL;
        }
    }
    return MPP_OK;
}
// using namespace std;
// int isOpen = false;
// const char * fifo_name = "/home/orangepi/code/live/testProgs/pipe.264";
// int pipe_fd;
// int mpp_packet_write_to_fifo(void *ptr, size_t len)
// {
//     int ret = 0;
//     if(!isOpen)
//     {
//         qDebug()<<"start open the fifo file\n";
//         pipe_fd = open(fifo_name, O_WRONLY);    //阻塞至读端打开
//         if(pipe_fd != -1)
//         {
//             qDebug()<<("open fifo success\n");
// //            qDebug()<<("thread mpp_packet_write_to_fifo, pipe_fd = %d\n", pipe_fd);
//             isOpen = true;
//             //return pipe_fd;
//         }
//         else
//         {
//             qDebug()<<("pipe file open error %s\n", strerror(errno));
//             return -1;
//             // pthread_exit(NULL);
//         }
//     }
//     ret = write(pipe_fd, ptr, len);
//     if(ret != len)
//     {
//         printf("=======Write fifo Err======\n");
//         return -1;
//     }
//     return 0;
// }
MPP_RET test_mpp_run(MpiEncMultiCtxInfo *info,cv::Mat pic,char* &fs,int & length)
{
    // MpiEncTestArgs *cmd = info->cmd;
    MpiEncTestData *p = &info->ctx;
    MppApi *mpi = p->mpi;
    MppCtx ctx = p->ctx;
    RK_U32 quiet = 0;
    RK_S32 chn = info->chn;
    RK_U32 cap_num = 0;
    DataCrc checkcrc;
    MPP_RET ret = MPP_OK;
    p->frame_count = 0;
    // 初始化 crc校验数据结构
    memset(&checkcrc, 0, sizeof(checkcrc));
    checkcrc.sum = mpp_malloc(RK_ULONG, 512);

    // 一次完整的调用 包括帧初始化 de初始化 还有填充 获取
    while (!p->pkt_eos) {
        MppMeta meta = NULL;
        MppFrame frame = NULL;
        MppPacket packet = NULL;
        void *buf = mpp_buffer_get_ptr(p->frm_buf);
        RK_S32 cam_frm_idx = -1;
        MppBuffer cam_buf = NULL;
        RK_U32 eoi = 1;

        // 数据实际输入
        int width = pic.rows;
        int height = pic.cols;

        int totalBytes = width * height * 3;  // 3个通道（BGR）每个通道占一个字节
        memcpy(buf, pic.data, totalBytes);
        // if (p->fp_input) {

        // 测试图像 2
        // int width = 1920;
        // int height = 1080;
        // // 创建一个空白图像，全黑
        // cv::Mat colorBar = cv::Mat::zeros(height, width, CV_8UC3);
        // // 设置彩条的宽度
        // int barWidth = width / 8; // 8个彩条，你可以根据需要调整
        // // 生成彩条
        // for (int i = 0; i < 8; ++i) {
        //     // 计算彩条的起始和结束位置
        //     int startX = i * barWidth;
        //     int endX = (i + 1) * barWidth;
        //     // 设置彩条颜色（BGR格式）
        //     cv::Vec3b color;
        //     if (i % 2 == 0) {
        //         color = cv::Vec3b(255, 0, 0); // 蓝色
        //     } else {
        //         color = cv::Vec3b(0, 255, 0); // 绿色
        //     }
        //     // 在图像上画出彩条
        //     colorBar(cv::Rect(startX, 0, barWidth, height)) = color;
        // }
        // int totalBytes = width * height * 3;  // 3个通道（BGR）每个通道占一个字节
        // memcpy(buf, colorBar.data, totalBytes);
        // 测试图像
        // ret = read_image((RK_U8*)buf, p->fp_input, p->width, p->height,
        //                     p->hor_stride, p->ver_stride, p->fmt);
        // buf  存储图片数据 ,fp_input 应该是一个文件的fp 明天再开
        if (ret == MPP_NOK ) {
            p->frm_eos = 1;
            // 判定是否满足结束标志 满足则加一个eos帧
            if (p->frame_num < 0 || p->frame_count < p->frame_num) {
                clearerr(p->fp_input);
                rewind(p->fp_input);
                p->frm_eos = 0;
                mpp_log_q(quiet, "chn %d loop times %d\n", chn, ++p->loop_times);
                continue;
            }
            mpp_log_q(quiet, "chn %d found last frame. feof %d\n", chn, feof(p->fp_input));
        } else if (ret == MPP_ERR_VALUE)
            goto RET;
        // }

        ret = mpp_frame_init(&frame);
        if (ret) {
            mpp_err_f("mpp_frame_init failed\n");
            goto RET;
        }

        mpp_frame_set_width(frame, p->width);
        mpp_frame_set_height(frame, p->height);
        mpp_frame_set_hor_stride(frame, p->hor_stride);
        mpp_frame_set_ver_stride(frame, p->ver_stride);
        mpp_frame_set_fmt(frame, p->fmt);
        mpp_frame_set_eos(frame, p->frm_eos);

     // 使用我的分配内存的frm_buf指针 填充Frame
        mpp_frame_set_buffer(frame, p->frm_buf);

        meta = mpp_frame_get_meta(frame);
        mpp_packet_init_with_buffer(&packet, p->pkt_buf);
        /* NOTE: It is important to clear output packet length!! */
        mpp_packet_set_length(packet, 0);
        mpp_meta_set_packet(meta, KEY_OUTPUT_PACKET, packet);
        mpp_meta_set_buffer(meta, KEY_MOTION_INFO, p->md_info);

        // if (p->osd_enable || p->user_data_enable || p->roi_enable) {
        //     if (p->user_data_enable) {
        //         MppEncUserData user_data;
        //         char *str = "this is user data\n";

        //         if ((p->frame_count & 10) == 0) {
        //             user_data.pdata = str;
        //             user_data.len = strlen(str) + 1;
        //             mpp_meta_set_ptr(meta, KEY_USER_DATA, &user_data);
        //         }
        //         static RK_U8 uuid_debug_info[16] = {
        //             0x57, 0x68, 0x97, 0x80, 0xe7, 0x0c, 0x4b, 0x65,
        //             0xa9, 0x06, 0xae, 0x29, 0x94, 0x11, 0xcd, 0x9a
        //         };

        //         MppEncUserDataSet data_group;
        //         MppEncUserDataFull datas[2];
        //         char *str1 = "this is user data 1\n";
        //         char *str2 = "this is user data 2\n";
        //         data_group.count = 2;
        //         datas[0].len = strlen(str1) + 1;
        //         datas[0].pdata = str1;
        //         datas[0].uuid = uuid_debug_info;

        //         datas[1].len = strlen(str2) + 1;
        //         datas[1].pdata = str2;
        //         datas[1].uuid = uuid_debug_info;

        //         data_group.datas = datas;

        //         mpp_meta_set_ptr(meta, KEY_USER_DATAS, &data_group);
        //     }

        //     if (p->osd_enable) {
        //         /* gen and cfg osd plt */
        //         mpi_enc_gen_osd_plt(&p->osd_plt, p->frame_count);

        //         p->osd_plt_cfg.change = MPP_ENC_OSD_PLT_CFG_CHANGE_ALL;
        //         p->osd_plt_cfg.type = MPP_ENC_OSD_PLT_TYPE_USERDEF;
        //         p->osd_plt_cfg.plt = &p->osd_plt;

        //         ret = mpi->control(ctx, MPP_ENC_SET_OSD_PLT_CFG, &p->osd_plt_cfg);
        //         if (ret) {
        //             mpp_err("mpi control enc set osd plt failed ret %d\n", ret);
        //             goto RET;
        //         }

        //         /* gen and cfg osd plt */
        //         mpi_enc_gen_osd_data(&p->osd_data, p->buf_grp, p->width,
        //                              p->height, p->frame_count);
        //         mpp_meta_set_ptr(meta, KEY_OSD_DATA, (void*)&p->osd_data);
        //     }

        //     if (p->roi_enable) {
        //         RoiRegionCfg *region = &p->roi_region;

        //         /* calculated in pixels */
        //         region->x = MPP_ALIGN(p->width / 8, 16);
        //         region->y = MPP_ALIGN(p->height / 8, 16);
        //         region->w = 128;
        //         region->h = 256;
        //         region->force_intra = 0;
        //         region->qp_mode = 1;
        //         region->qp_val = 24;

        //         mpp_enc_roi_add_region(p->roi_ctx, region);

        //         region->x = MPP_ALIGN(p->width / 2, 16);
        //         region->y = MPP_ALIGN(p->height / 4, 16);
        //         region->w = 256;
        //         region->h = 128;
        //         region->force_intra = 1;
        //         region->qp_mode = 1;
        //         region->qp_val = 10;

        //         mpp_enc_roi_add_region(p->roi_ctx, region);

        //         /* send roi info by metadata */
        //         mpp_enc_roi_setup_meta(p->roi_ctx, meta);
        //     }
        // }

        if (!p->first_frm)
            p->first_frm = mpp_time();
        /*
         * NOTE: in non-block mode the frame can be resent.
         * The default input timeout mode is block.
         *
         * User should release the input frame to meet the requirements of
         * resource creator must be the resource destroyer.
         */
        ret = mpi->encode_put_frame(ctx, frame);
        if (ret) {
            mpp_err("chn %d encode put frame failed\n", chn);
            mpp_frame_deinit(&frame);
            goto RET;
        }

        mpp_frame_deinit(&frame);

        do {
            ret = mpi->encode_get_packet(ctx, &packet);
            if (ret) {
                mpp_err("chn %d encode get packet failed\n", chn);
                goto RET;
            }

            mpp_assert(packet);

            if (packet) {
                // write packet to file here
                void *ptr   = mpp_packet_get_pos(packet);
                size_t len  = mpp_packet_get_length(packet);
                char log_buf[256];
                RK_S32 log_size = sizeof(log_buf) - 1;
                RK_S32 log_len = 0;

                if (!p->first_pkt)
                    p->first_pkt = mpp_time();

                p->pkt_eos = mpp_packet_get_eos(packet);

                if (p->fp_output){
                     fwrite(ptr, 1, len, p->fp_output);
                    fs = (char*)malloc(len*sizeof(char));

                    memcpy(fs, ptr, len);
                    length = len;
                    // fs = (char*)cpy;
                    //pipe close
//                     if(mpp_packet_write_to_fifo(cpy, len) < 0)//阻塞
//                    {
//                        // goto RET;
//                        printf(" mpp_packet_write_to_fifo err \n");
//                    }
                    // timeval ref;
                    // gettimeofday(&ref, NULL);
                    // fs->postFrame((char*)cpy,len,ref);
                }

                if (p->fp_verify && !p->pkt_eos) {
                    calc_data_crc((RK_U8 *)ptr, (RK_U32)len, &checkcrc);
                    mpp_log("p->frame_count=%d, len=%d\n", p->frame_count, len);
                    write_data_crc(p->fp_verify, &checkcrc);
                }

                log_len += snprintf(log_buf + log_len, log_size - log_len,
                                    "encoded frame %-4d", p->frame_count);

                /* for low delay partition encoding */
                if (mpp_packet_is_partition(packet)) {
                    eoi = mpp_packet_is_eoi(packet);

                    log_len += snprintf(log_buf + log_len, log_size - log_len,
                                        " pkt %d", p->frm_pkt_cnt);
                    p->frm_pkt_cnt = (eoi) ? (0) : (p->frm_pkt_cnt + 1);
                }

                log_len += snprintf(log_buf + log_len, log_size - log_len,
                                    " size %-7zu", len);

                if (mpp_packet_has_meta(packet)) {
                    meta = mpp_packet_get_meta(packet);
                    RK_S32 temporal_id = 0;
                    RK_S32 lt_idx = -1;
                    RK_S32 avg_qp = -1;

                    if (MPP_OK == mpp_meta_get_s32(meta, KEY_TEMPORAL_ID, &temporal_id))
                        log_len += snprintf(log_buf + log_len, log_size - log_len,
                                            " tid %d", temporal_id);

                    if (MPP_OK == mpp_meta_get_s32(meta, KEY_LONG_REF_IDX, &lt_idx))
                        log_len += snprintf(log_buf + log_len, log_size - log_len,
                                            " lt %d", lt_idx);

                    if (MPP_OK == mpp_meta_get_s32(meta, KEY_ENC_AVERAGE_QP, &avg_qp))
                        log_len += snprintf(log_buf + log_len, log_size - log_len,
                                            " qp %d", avg_qp);
                }

                // mpp_log_q(quiet, "chn %d %s\n", chn, log_buf);

                mpp_packet_deinit(&packet);
                // fps_calc_inc(p->fps_out_num);

                p->stream_size += len;
                p->frame_count += eoi;

                if (p->pkt_eos) {
                    mpp_log_q(quiet, "chn %d found last packet\n", chn);
                    mpp_assert(p->frm_eos);
                }
            }
        } while (!eoi);


        if (p->frame_num > 0 && p->frame_count >= p->frame_num)
            break;


        if (p->frm_eos && p->pkt_eos)
            break;
    }
RET:
    MPP_FREE(checkcrc.sum);

    return ret;
}

encoder::encoder()
{

}



int encoder::init(char * &fs,int &size)
{

    memset(this->info,0,sizeof(MpiEncMultiCtxInfo));
    MpiEncTestData *p = &info->ctx;
    MpiEncMultiCtxRet *enc_ret = &info->ret;
    MppApi *mpi = p->mpi;
    MppCtx ctx = p->ctx;
    MppPollType timeout = MPP_POLL_BLOCK;
    MPP_RET ret = MPP_OK;
    RK_S64 t_s = 0;
    RK_S64 t_e = 0;
    RK_U32 quiet ;
    ret = test_ctx_init(info);
    if (ret) {
        mpp_err_f("test data init failed ret %d\n", ret);
        goto MPP_TEST_OUT;
    }
    ret = mpp_buffer_group_get_internal(&p->buf_grp, MPP_BUFFER_TYPE_DRM);
    if (ret) {
        mpp_err_f("failed to get mpp buffer group ret %d\n", ret);
        goto MPP_TEST_OUT;
    }
    ret = mpp_buffer_get(p->buf_grp, &p->frm_buf, p->frame_size + p->header_size);
    if (ret) {
        mpp_err_f("failed to get buffer for input frame ret %d\n", ret);
        goto MPP_TEST_OUT;
    }
    ret = mpp_buffer_get(p->buf_grp, &p->pkt_buf, p->frame_size);
    if (ret) {
        mpp_err_f("failed to get buffer for output packet ret %d\n", ret);
        goto MPP_TEST_OUT;
    }

    ret = mpp_buffer_get(p->buf_grp, &p->md_info, p->mdinfo_size);
    if (ret) {
        mpp_err_f("failed to get buffer for motion info output packet ret %d\n", ret);
        goto MPP_TEST_OUT;
    }
    // encoder demo
    ret = mpp_create(&p->ctx, &p->mpi);
    if (ret) {
        mpp_err("mpp_create failed ret %d\n", ret);
        goto MPP_TEST_OUT;
    }
    mpp_log_q(quiet, "%p encoder test start w %d h %d type %d\n",
              p->ctx, p->width, p->height, p->type);

    ret = p->mpi->control(p->ctx, MPP_SET_OUTPUT_TIMEOUT, &timeout);
    if (MPP_OK != ret) {
        mpp_err("mpi control set output timeout %d ret %d\n", timeout, ret);
        goto MPP_TEST_OUT;
    }

    ret = mpp_init(p->ctx, MPP_CTX_ENC, p->type);
    if (ret) {
        mpp_err("mpp_init failed ret %d\n", ret);
        goto MPP_TEST_OUT;
    }
    ret = mpp_enc_cfg_init(&p->cfg);
    if (ret) {
        mpp_err_f("mpp_enc_cfg_init failed ret %d\n", ret);
        goto MPP_TEST_OUT;
    }

    ret = p->mpi->control(p->ctx, MPP_ENC_GET_CFG, p->cfg);
    if (ret) {
        mpp_err_f("get enc cfg failed ret %d\n", ret);
        goto MPP_TEST_OUT;
    }

    ret = test_mpp_enc_cfg_setup(info);
    if (ret) {
        mpp_err_f("test mpp setup failed ret %d\n", ret);
        goto MPP_TEST_OUT;
    }

    p->pkt_eos = 0;
    // prepare a frame head


    if (p->type == MPP_VIDEO_CodingAVC || p->type == MPP_VIDEO_CodingHEVC) {
        MppPacket packet = NULL;

        /*
         * Can use packet with normal malloc buffer as input not pkt_buf.
         * Please refer to vpu_api_legacy.cpp for normal buffer case.
         * Using pkt_buf buffer here is just for simplifing demo.
         */
        mpp_packet_init_with_buffer(&packet, p->pkt_buf);
        /* NOTE: It is important to clear output packet length!! */
        mpp_packet_set_length(packet, 0);

        ret = p->mpi->control(p->ctx, MPP_ENC_GET_HDR_SYNC, packet);
        if (ret) {
            mpp_err("mpi control enc get extra info failed\n");
            // goto RET;
        } else {
            /* get and write sps/pps for H.264 */

            void *ptr   = mpp_packet_get_pos(packet);
            size_t len  = mpp_packet_get_length(packet);

            if (p->fp_output)
                fs = (char*)malloc(len*sizeof(char));
                memcpy(fs, ptr, len);
                size = len;
                 fwrite(ptr, 1, len, p->fp_output);
        }

        mpp_packet_deinit(&packet);
        return 1;
    }




MPP_TEST_OUT:
    if (p->ctx) {
        mpp_destroy(p->ctx);
        p->ctx = NULL;
    }

    if (p->cfg) {
        mpp_enc_cfg_deinit(p->cfg);
        p->cfg = NULL;
    }

    if (p->frm_buf) {
        mpp_buffer_put(p->frm_buf);
        p->frm_buf = NULL;
    }

    if (p->pkt_buf) {
        mpp_buffer_put(p->pkt_buf);
        p->pkt_buf = NULL;
    }

    if (p->md_info) {
        mpp_buffer_put(p->md_info);
        p->md_info = NULL;
    }

    if (p->osd_data.buf) {
        mpp_buffer_put(p->osd_data.buf);
        p->osd_data.buf = NULL;
    }

    if (p->buf_grp) {
        mpp_buffer_group_put(p->buf_grp);
        p->buf_grp = NULL;
    }



    test_ctx_deinit(p);

    return 0;
}
MPP_RET encoder::postAframe(cv::Mat pic,char* &fs,int & length ){
    MPP_RET ret = MPP_NOK;
    MpiEncTestData *p = &info->ctx;

    ret = test_mpp_run(info,pic,fs,length);

POST_OUT:
    return ret;


}
int encoder::deinit(MPP_RET ret = MPP_OK){
    MpiEncTestData *p = &info->ctx;
    if (ret) {
        mpp_err_f("test mpp run failed ret %d\n", ret);
        goto POST_OUT;
    }

    ret = p->mpi->reset(p->ctx);
    if (ret) {
        mpp_err("mpi->reset failed\n");
        goto POST_OUT;
    }


POST_OUT:
    // return ret;
if (p->ctx) {
        mpp_destroy(p->ctx);
        p->ctx = NULL;
    }

    if (p->cfg) {
        mpp_enc_cfg_deinit(p->cfg);
        p->cfg = NULL;
    }

    if (p->frm_buf) {
        mpp_buffer_put(p->frm_buf);
        p->frm_buf = NULL;
    }

    if (p->pkt_buf) {
        mpp_buffer_put(p->pkt_buf);
        p->pkt_buf = NULL;
    }

    if (p->md_info) {
        mpp_buffer_put(p->md_info);
        p->md_info = NULL;
    }

    if (p->osd_data.buf) {
        mpp_buffer_put(p->osd_data.buf);
        p->osd_data.buf = NULL;
    }

    if (p->buf_grp) {
        mpp_buffer_group_put(p->buf_grp);
        p->buf_grp = NULL;
    }



    test_ctx_deinit(p);

    return 0;

}
encoder::~encoder(){


}


